package org.raftkv.raft.core.storage;

import org.raftkv.commons.Tuple;
import org.raftkv.raft.pb.ConfState;
import org.raftkv.raft.pb.Entry;
import org.raftkv.raft.pb.HardState;
import org.raftkv.raft.pb.Snapshot;

import java.util.List;

/**
 * 应用程序可以实现该接口，用于从存储中检索日志条目。
 * <br/>
 * 如果任何存储方法返回错误，Raft 实例将变得无法运行并拒绝参与选举；在这种情况下，应用程序负责清理和恢复。
 *
 * @author wzy
 */
public interface Storage {

    /**
     * initialState() 函数返回保存的 HardState 和 ConfState 信息
     */
    Tuple<HardState, ConfState> initialState();

    /**
     * entries() 函数返回范围 [lo，hi) 中的日志条目片段
     *
     * @param maxSize maxSize 限制返回的日志条目的总大小，但至少会返回一个 entry（如果有）。
     */
    List<Entry> entries(long lo, long hi, long maxSize);

    /**
     * term() 函数返回 entry index 的任期，term 必须在 [firstIndex() - 1, lastIndex()] 范围内。
     * <br/>
     * firstIndex() 之前的 entry term 将保留用于匹配提案，即使该 entry 的其余部分可能不可用。
     */
    long term(long index);

    /**
     * firstIndex() 函数返回可能通过 entries() 函数获得的第一个 entry 的 index。
     * <br/>
     * （较旧的 entries 已合并到最新的 snapshot 中；如果存储仅包含虚拟 entry，则第一个 log entry 不可用）
     */
    long firstIndex();

    /**
     * lastIndex() 返回最后一条日志的索引值。
     */
    long lastIndex();

    /**
     * snapshot() 函数返回最新的快照数据。
     * <br/>
     * 如果快照暂时不可用，这个函数应该抛出 SnapshotTemporarilyUnavailableException，
     * Raft 状态机就可以感知到 Storage 需要一些时间准备快照，过一段时间之后再调用该函数。
     */
    Snapshot snapshot();

}
